package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.dto.StageAddDTO;
import com.ruoyi.system.dto.StageQueryDTO;
import com.ruoyi.system.dto.StageUpdateDTO;
import com.ruoyi.system.entity.ConstructionStageDO;
import com.ruoyi.system.entity.ConstructionProjectStageRelDO;
import com.ruoyi.system.mapper.ConstructionStageMapper;
import com.ruoyi.system.mapper.ConstructionProjectStageRelMapper;
import com.ruoyi.system.service.ConstructionStageService;
import com.ruoyi.system.service.IProjectStageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 施工阶段配置Service实现
 */
@Service
public class ConstructionStageServiceImpl extends ServiceImpl<ConstructionStageMapper, ConstructionStageDO>
        implements ConstructionStageService {

    @Resource
    private ConstructionStageMapper stageMapper;

    @Resource
    private ConstructionProjectStageRelMapper constructionProjectStageRelMapper;

    @Resource
    private IProjectStageService projectStageService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addCustomStage(StageAddDTO dto, String designerId, String operator) {
        // 1. 校验阶段名称唯一性（不可与固定/自定义阶段重复）
        Integer nameCount = stageMapper.checkStageNameExist(dto.getStageName(), null);
        if (nameCount != null && nameCount > 0) {
            throw new ServiceException("阶段名称“" + dto.getStageName() + "”已存在，请重新输入");
        }

        // 2. 生成自定义阶段编号（ZD + 3位流水号，如ZD001）
        String stageCode = generateStageCode(2);

        // 3. 构建阶段DO并保存
        ConstructionStageDO stageDO = new ConstructionStageDO();
        stageDO.setStageCode(stageCode);
        stageDO.setStageName(dto.getStageName());
        stageDO.setStageType(2); // 2-自定义阶段
        stageDO.setIsRequired(dto.getIsRequired());
        stageDO.setSortNum(dto.getSortNum());
        stageDO.setStageStatus(dto.getStageStatus() == null ? 1 : dto.getStageStatus()); // 默认启用
        stageDO.setDesignerId(designerId);
        stageDO.setRemark(dto.getRemark());
        stageDO.setCreateBy(operator);
        stageDO.setUpdateBy(operator);
        save(stageDO);

        return stageDO.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStage(StageUpdateDTO dto, String operator) {
        // 1. 校验阶段是否存在
        Long stageId = dto.getStageId();
        ConstructionStageDO existStage = getById(stageId);
        if (existStage == null) {
            throw new ServiceException("施工阶段不存在");
        }

        // 2. 区分固定阶段与自定义阶段的修改权限
        Integer stageType = existStage.getStageType();
        ConstructionStageDO updateDO = new ConstructionStageDO();
        updateDO.setId(stageId);
        updateDO.setUpdateBy(operator);

        // 2.1 固定阶段（1）：仅可修改“是否必选”和“状态”
        if (stageType == 1) {
            updateDO.setIsRequired(dto.getIsRequired());
            // 若修改为停用，需校验是否关联项目
            if (dto.getStageStatus() != null && dto.getStageStatus() == 2) {
                Integer relatedCount = stageMapper.getRelatedProjectCount(stageId);
                if (relatedCount != null && relatedCount > 0) {
                    throw new ServiceException("该阶段已关联" + relatedCount + "个项目，不可停用");
                }
            }
            updateDO.setStageStatus(dto.getStageStatus());
        }
        // 2.2 自定义阶段（2）：可修改所有字段（名称需校验唯一性）
        else {
            // 阶段名称修改需校验唯一性
            if (dto.getStageName() != null && !dto.getStageName().equals(existStage.getStageName())) {
                Integer nameCount = stageMapper.checkStageNameExist(dto.getStageName(), stageId);
                if (nameCount != null && nameCount > 0) {
                    throw new ServiceException("阶段名称“" + dto.getStageName() + "”已存在，请重新输入");
                }
                updateDO.setStageName(dto.getStageName());
            }
            updateDO.setIsRequired(dto.getIsRequired());
            updateDO.setSortNum(dto.getSortNum());
            // 若修改为停用，需校验是否关联项目
            if (dto.getStageStatus() != null && dto.getStageStatus() == 2) {
                Integer relatedCount = stageMapper.getRelatedProjectCount(stageId);
                if (relatedCount != null && relatedCount > 0) {
                    throw new ServiceException("该阶段已关联" + relatedCount + "个项目，不可停用");
                }
            }
            updateDO.setStageStatus(dto.getStageStatus());
            updateDO.setRemark(dto.getRemark());
        }

        // 3. 执行更新
        updateById(updateDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCustomStage(Long stageId) {
        // 1. 校验阶段是否存在且为自定义阶段
        ConstructionStageDO existStage = getById(stageId);
        if (existStage == null) {
            throw new ServiceException("施工阶段不存在");
        }
        if (existStage.getStageType() == 1) {
            throw new ServiceException("固定阶段不可删除");
        }

        // 2. 校验是否关联项目
        Integer relatedCount = stageMapper.getRelatedProjectCount(stageId);
        if (relatedCount != null && relatedCount > 0) {
            throw new ServiceException("该阶段已关联" + relatedCount + "个项目，不可删除");
        }

        // 3. 逻辑删除（MyBatis-Plus自动处理is_deleted字段）
        removeById(stageId);
    }

    @Override
    public Page<ConstructionStageDO> queryStagePage(StageQueryDTO queryDTO) {
        Page<ConstructionStageDO> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        LambdaQueryWrapper<ConstructionStageDO> wrapper = new LambdaQueryWrapper<>();

        // 阶段名称模糊搜索
        if (queryDTO.getStageName() != null && !queryDTO.getStageName().isEmpty()) {
            wrapper.like(ConstructionStageDO::getStageName, queryDTO.getStageName());
        }

        // 状态筛选
        if (queryDTO.getStageStatus() != null) {
            wrapper.eq(ConstructionStageDO::getStageStatus, queryDTO.getStageStatus());
        }

        // 获取当前设计师ID（假设DTO中已包含，若可能为空需补充非空判断）
        String designerId = queryDTO.getDesignerId();
        Integer stageType = queryDTO.getStageType();

        // 核心：根据StageType构建不同的查询条件
        if (stageType == null) {
            // 情况1：StageType为空 → 固定阶段（1）+ 当前设计师的自定义阶段（2）
            wrapper.and(i -> i
                    .eq(ConstructionStageDO::getStageType, 1) // 固定阶段
                    .or(j -> j
                            .eq(ConstructionStageDO::getStageType, 2) // 自定义阶段
                            .eq(ConstructionStageDO::getDesignerId, designerId) // 且属于当前设计师
                    )
            );
        } else if (stageType == 1) {
            // 情况2：StageType=1 → 只查固定阶段
            wrapper.eq(ConstructionStageDO::getStageType, 1);
        } else if (stageType == 2) {
            // 情况3：StageType=2 → 只查当前设计师的自定义阶段
            wrapper.eq(ConstructionStageDO::getStageType, 2)
                    .eq(ConstructionStageDO::getDesignerId, designerId);
        }

        // 排序（保留原逻辑）
        wrapper.orderByAsc(ConstructionStageDO::getSortNum)
                .orderByDesc(ConstructionStageDO::getCreateTime);

        // 执行分页查询
        Page<ConstructionStageDO> result = page(page, wrapper);
        List<ConstructionStageDO> records = result.getRecords();

        // 补充关联项目数量（保留原逻辑）
        if (!records.isEmpty()) {
            records.forEach(x -> {
                Long count = projectStageService.lambdaQuery()
                        .eq(ConstructionProjectStageRelDO::getStageId, x.getId())
                        .count();
                x.setAssociatedProjectCount(count.intValue());
            });
            result.setRecords(records);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchBindProjects(List<Long> stageIdList, List<Long> projectIdList, String operator) {
        if (CollectionUtils.isEmpty(stageIdList) || CollectionUtils.isEmpty(projectIdList)) {
            throw new ServiceException("阶段ID列表和项目ID列表不可为空");
        }

        // 1. 校验阶段是否启用（已停用阶段不可绑定）
        List<ConstructionStageDO> stageList = listByIds(stageIdList);
        List<Long> invalidStageIds = stageList.stream()
                .filter(stage -> stage.getStageStatus() != 1)
                .map(ConstructionStageDO::getId)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(invalidStageIds)) {
            throw new ServiceException("阶段ID：" + invalidStageIds + " 已停用，不可绑定项目");
        }

        for (Long stageId : stageIdList) {
            for (Long projectId : projectIdList) {
                if (constructionProjectStageRelMapper.exists(new LambdaQueryWrapper<ConstructionProjectStageRelDO>()
                        .eq(ConstructionProjectStageRelDO::getStageId, stageId)
                        .eq(ConstructionProjectStageRelDO::getProjectId, projectId)
                        .eq(ConstructionProjectStageRelDO::getIsDeleted, 0))) {
                    throw new ServiceException("存在重复绑定阶段,请重新选择");
                }

            }
        }

        // 2. 批量插入关联关系（先查已存在的关联，避免重复）
        List<ConstructionProjectStageRelDO> relList = stageIdList.stream().flatMap(stageId ->
                projectIdList.stream().map(projectId -> {
                    ConstructionProjectStageRelDO relDO = new ConstructionProjectStageRelDO();
                    relDO.setProjectId(projectId);
                    relDO.setStageId(stageId);
                    relDO.setStageStatus(0); // 初始状态：未开始
                    return relDO;
                })
        ).collect(Collectors.toList());

        // 批量插入（需处理重复键冲突，可通过ON DUPLICATE KEY UPDATE忽略）
        if (!CollectionUtils.isEmpty(relList)) {
            constructionProjectStageRelMapper.batchInsert(relList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUnbindProjects(List<Long> stageIdList, List<Long> projectIdList) {
        if (CollectionUtils.isEmpty(stageIdList) || CollectionUtils.isEmpty(projectIdList)) {
            throw new ServiceException("阶段ID列表和项目ID列表不可为空");
        }

        // 1. 校验阶段是否已完成（已完成阶段不可解除绑定）
        for (Long projectId : projectIdList) {
            List<Long> completedStageIds = constructionProjectStageRelMapper.getCompletedStageIds(projectId);
            List<Long> completedInvalidIds = stageIdList.stream()
                    .filter(completedStageIds::contains)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(completedInvalidIds)) {
                throw new ServiceException("项目ID：" + projectId + " 中阶段ID：" + completedInvalidIds + " 已完成，不可解除绑定");
            }
        }

        // 2. 批量删除关联关系
        for (Long projectId : projectIdList) {
            constructionProjectStageRelMapper.deleteByProjectIdAndStageIds(projectId, stageIdList);
        }
    }

    @Override
    public boolean checkStagesValid(List<Long> stageIdList) {
        if (CollectionUtils.isEmpty(stageIdList)) {
            return false;
        }


        // 1. 查询阶段列表（过滤已删除）
        LambdaQueryWrapper<ConstructionStageDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ConstructionStageDO::getId, stageIdList)
                .eq(ConstructionStageDO::getIsDeleted, 0)
                .eq(ConstructionStageDO::getStageStatus, 1); // 仅查询启用状态

        List<ConstructionStageDO> validStageList = list(wrapper);
        // 2. 对比传入的阶段ID列表与查询到的有效阶段ID列表，判断是否全部有效
        return validStageList.size() == stageIdList.size();
    }

    @Override
    public String generateStageCode(Integer stageType) {
        // 1. 确定前缀（固定阶段GD，自定义阶段ZD）
        String prefix = stageType == 1 ? "GD" : "ZD";
        // 2. 查询当前前缀下的最大编号
        LambdaQueryWrapper<ConstructionStageDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.likeRight(ConstructionStageDO::getStageCode, prefix)
                .orderByDesc(ConstructionStageDO::getStageCode)
                .last("LIMIT 1");

        ConstructionStageDO maxStage = getOne(wrapper);
        // 3. 生成3位流水号（默认从001开始）
        String seqStr;
        if (maxStage == null) {
            seqStr = "001";
        } else {
            String maxCode = maxStage.getStageCode();
            int seq = Integer.parseInt(maxCode.substring(prefix.length())) + 1;
            seqStr = String.format("%03d", seq);
        }
        // 4. 拼接阶段编号
        return prefix + seqStr;
    }
}